home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / Undo.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  20.7 KB  |  864 lines

  1.  
  2. /*
  3.  
  4.   QERadiant Undo/Redo
  5.  
  6.  
  7. basic setup:
  8.  
  9. <-g_undolist---------g_lastundo> <---map data---> <-g_lastredo---------g_redolist->
  10.  
  11.  
  12.   undo/redo on the world_entity is special, only the epair changes are remembered
  13.   and the world entity never gets deleted.
  14.  
  15.   FIXME: maybe reset the Undo system at map load
  16.          maybe also reset the entityId at map load
  17. */
  18.  
  19. #include "stdafx.h"
  20. #include "Radiant.h"
  21. #include "qe3.h"
  22.  
  23. typedef struct undo_s
  24. {
  25.     double time;                //time operation was performed
  26.     int id;                        //every undo has an unique id
  27.     int done;                    //true when undo is build
  28.     char *operation;            //name of the operation
  29.     brush_t brushlist;            //deleted brushes
  30.     entity_t entitylist;        //deleted entities
  31.     struct undo_s *prev, *next;    //next and prev undo in list
  32. } undo_t;
  33.  
  34. undo_t *g_undolist;                        //first undo in the list
  35. undo_t *g_lastundo;                        //last undo in the list
  36. undo_t *g_redolist;                        //first redo in the list
  37. undo_t *g_lastredo;                        //last undo in list
  38. int g_undoMaxSize = 64;                    //maximum number of undos
  39. int g_undoSize = 0;                        //number of undos in the list
  40. int g_undoMaxMemorySize = 2*1024*1024;    //maximum undo memory (default 2 MB)
  41. int g_undoMemorySize = 0;                //memory size of undo buffer
  42. int g_undoId = 1;                        //current undo ID (zero is invalid id)
  43. int g_redoId = 1;                        //current redo ID (zero is invalid id)
  44.  
  45.  
  46. /*
  47. =============
  48. Undo_MemorySize
  49. =============
  50. */
  51. int Undo_MemorySize(void)
  52. {
  53.     /*
  54.     int size;
  55.     undo_t *undo;
  56.     brush_t *pBrush;
  57.     entity_t *pEntity;
  58.  
  59.     size = 0;
  60.     for (undo = g_undolist; undo; undo = undo->next)
  61.     {
  62.         for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pBrush->next)
  63.         {
  64.             size += Brush_MemorySize(pBrush);
  65.         }
  66.         for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pEntity->next)
  67.         {
  68.             size += Entity_MemorySize(pEntity);
  69.         }
  70.         size += sizeof(undo_t);
  71.     }
  72.     return size;
  73.     */
  74.     return g_undoMemorySize;
  75. }
  76.  
  77. /*
  78. =============
  79. Undo_ClearRedo
  80. =============
  81. */
  82. void Undo_ClearRedo(void)
  83. {
  84.     undo_t *redo, *nextredo;
  85.     brush_t *pBrush, *pNextBrush;
  86.     entity_t *pEntity, *pNextEntity;
  87.  
  88.     for (redo = g_redolist; redo; redo = nextredo)
  89.     {
  90.         nextredo = redo->next;
  91.         for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush)
  92.         {
  93.             pNextBrush = pBrush->next;
  94.             Brush_Free(pBrush);
  95.         }
  96.         for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity)
  97.         {
  98.             pNextEntity = pEntity->next;
  99.             Entity_Free(pEntity);
  100.         }
  101.         free(redo);
  102.     }
  103.     g_redolist = NULL;
  104.     g_lastredo = NULL;
  105.     g_redoId = 1;
  106. }
  107.  
  108. /*
  109. =============
  110. Undo_Clear
  111.  
  112.   Clears the undo buffer.
  113. =============
  114. */
  115. void Undo_Clear(void)
  116. {
  117.     undo_t *undo, *nextundo;
  118.     brush_t *pBrush, *pNextBrush;
  119.     entity_t *pEntity, *pNextEntity;
  120.  
  121.     Undo_ClearRedo();
  122.     for (undo = g_undolist; undo; undo = nextundo)
  123.     {
  124.         nextundo = undo->next;
  125.         for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush)
  126.         {
  127.             pNextBrush = pBrush->next;
  128.             g_undoMemorySize -= Brush_MemorySize(pBrush);
  129.             Brush_Free(pBrush);
  130.         }
  131.         for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
  132.         {
  133.             pNextEntity = pEntity->next;
  134.             g_undoMemorySize -= Entity_MemorySize(pEntity);
  135.             Entity_Free(pEntity);
  136.         }
  137.         g_undoMemorySize -= sizeof(undo_t);
  138.         free(undo);
  139.     }
  140.     g_undolist = NULL;
  141.     g_lastundo = NULL;
  142.     g_undoSize = 0;
  143.     g_undoMemorySize = 0;
  144.     g_undoId = 1;
  145. }
  146.  
  147. /*
  148. =============
  149. Undo_SetMaxSize
  150. =============
  151. */
  152. void Undo_SetMaxSize(int size)
  153. {
  154.     Undo_Clear();
  155.     if (size < 1) g_undoMaxSize = 1;
  156.     else g_undoMaxSize = size;
  157. }
  158.  
  159. /*
  160. =============
  161. Undo_GetMaxSize
  162. =============
  163. */
  164. int Undo_GetMaxSize(void)
  165. {
  166.     return g_undoMaxSize;
  167. }
  168.  
  169. /*
  170. =============
  171. Undo_SetMaxMemorySize
  172. =============
  173. */
  174. void Undo_SetMaxMemorySize(int size)
  175. {
  176.     Undo_Clear();
  177.     if (size < 1024) g_undoMaxMemorySize = 1024;
  178.     else g_undoMaxMemorySize = size;
  179. }
  180.  
  181. /*
  182. =============
  183. Undo_GetMaxMemorySize
  184. =============
  185. */
  186. int Undo_GetMaxMemorySize(void)
  187. {
  188.     return g_undoMaxMemorySize;
  189. }
  190.  
  191. /*
  192. =============
  193. Undo_FreeFirstUndo
  194. =============
  195. */
  196. void Undo_FreeFirstUndo(void)
  197. {
  198.     undo_t *undo;
  199.     brush_t *pBrush, *pNextBrush;
  200.     entity_t *pEntity, *pNextEntity;
  201.  
  202.     //remove the oldest undo from the undo buffer
  203.     undo = g_undolist;
  204.     g_undolist = g_undolist->next;
  205.     g_undolist->prev = NULL;
  206.     //
  207.     for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush)
  208.     {
  209.         pNextBrush = pBrush->next;
  210.         g_undoMemorySize -= Brush_MemorySize(pBrush);
  211.         Brush_Free(pBrush);
  212.     }
  213.     for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity)
  214.     {
  215.         pNextEntity = pEntity->next;
  216.         g_undoMemorySize -= Entity_MemorySize(pEntity);
  217.         Entity_Free(pEntity);
  218.     }
  219.     g_undoMemorySize -= sizeof(undo_t);
  220.     free(undo);
  221.     g_undoSize--;
  222. }
  223.  
  224. /*
  225. =============
  226. Undo_GeneralStart
  227. =============
  228. */
  229. void Undo_GeneralStart(char *operation)
  230. {
  231.     undo_t *undo;
  232.     brush_t *pBrush;
  233.     entity_t *pEntity;
  234.  
  235.  
  236.     if (g_lastundo)
  237.     {
  238.         if (!g_lastundo->done)
  239.         {
  240.             Sys_Printf("Undo_Start: WARNING last undo not finished.\n");
  241.         }
  242.     }
  243.  
  244.     undo = (undo_t *) malloc(sizeof(undo_t));
  245.     if (!undo) return;
  246.     memset(undo, 0, sizeof(undo_t));
  247.     undo->brushlist.next = &undo->brushlist;
  248.     undo->brushlist.prev = &undo->brushlist;
  249.     undo->entitylist.next = &undo->entitylist;
  250.     undo->entitylist.prev = &undo->entitylist;
  251.     if (g_lastundo) g_lastundo->next = undo;
  252.     else g_undolist = undo;
  253.     undo->prev = g_lastundo;
  254.     undo->next = NULL;
  255.     g_lastundo = undo;
  256.     
  257.     undo->time = Sys_DoubleTime();
  258.     //
  259.     if (g_undoId > g_undoMaxSize * 2) g_undoId = 1;
  260.     if (g_undoId <= 0) g_undoId = 1;
  261.     undo->id = g_undoId++;
  262.     undo->done = false;
  263.     undo->operation = operation;
  264.     //reset the undo IDs of all brushes using the new ID
  265.     for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next)
  266.     {
  267.         if (pBrush->undoId == undo->id)
  268.         {
  269.             pBrush->undoId = 0;
  270.         }
  271.     }
  272.     for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next)
  273.     {
  274.         if (pBrush->undoId == undo->id)
  275.         {
  276.             pBrush->undoId = 0;
  277.         }
  278.     }
  279.     //reset the undo IDs of all entities using thew new ID
  280.     for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
  281.     {
  282.         if (pEntity->undoId == undo->id)
  283.         {
  284.             pEntity->undoId = 0;
  285.         }
  286.     }
  287.     g_undoMemorySize += sizeof(undo_t);
  288.     g_undoSize++;
  289.     //undo buffer is bound to a max
  290.     if (g_undoSize > g_undoMaxSize)
  291.     {
  292.         Undo_FreeFirstUndo();
  293.     }
  294. }
  295.  
  296. /*
  297. =============
  298. Undo_BrushInUndo
  299. =============
  300. */
  301. int Undo_BrushInUndo(undo_t *undo, brush_t *brush)
  302. {
  303.     brush_t *b;
  304.  
  305.     for (b = undo->brushlist.next; b != &undo->brushlist; b = b->next)
  306.     {
  307.         if (b == brush) return true;
  308.     }
  309.     return false;
  310. }
  311.  
  312. /*
  313. =============
  314. Undo_EntityInUndo
  315. =============
  316. */
  317. int Undo_EntityInUndo(undo_t *undo, entity_t *ent)
  318. {
  319.     entity_t *e;
  320.  
  321.     for (e = undo->entitylist.next; e != &undo->entitylist; e = e->next)
  322.     {
  323.         if (e == ent) return true;
  324.     }
  325.     return false;
  326. }
  327.  
  328. /*
  329. =============
  330. Undo_Start
  331. =============
  332. */
  333. void Undo_Start(char *operation)
  334. {
  335.     Undo_ClearRedo();
  336.     Undo_GeneralStart(operation);
  337. }
  338.  
  339. /*
  340. =============
  341. Undo_AddBrush
  342. =============
  343. */
  344. void Undo_AddBrush(brush_t *pBrush)
  345. {
  346.     if (!g_lastundo)
  347.     {
  348.         Sys_Printf("Undo_AddBrushList: no last undo.\n");
  349.         return;
  350.     }
  351.     if (g_lastundo->entitylist.next != &g_lastundo->entitylist)
  352.     {
  353.         Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n");
  354.     }
  355.     //if the brush is already in the undo
  356.     if (Undo_BrushInUndo(g_lastundo, pBrush))
  357.         return;
  358.     //clone the brush
  359.     brush_t* pClone = Brush_FullClone(pBrush);
  360.     //save the ID of the owner entity
  361.     pClone->ownerId = pBrush->owner->entityId;
  362.     //save the old undo ID for previous undos
  363.     pClone->undoId = pBrush->undoId;
  364.     Brush_AddToList (pClone, &g_lastundo->brushlist);
  365.     //
  366.     g_undoMemorySize += Brush_MemorySize(pClone);
  367. }
  368.  
  369. /*
  370. =============
  371. Undo_AddBrushList
  372. =============
  373. */
  374. void Undo_AddBrushList(brush_t *brushlist)
  375. {
  376.     brush_t *pBrush;
  377.  
  378.     if (!g_lastundo)
  379.     {
  380.         Sys_Printf("Undo_AddBrushList: no last undo.\n");
  381.         return;
  382.     }
  383.     if (g_lastundo->entitylist.next != &g_lastundo->entitylist)
  384.     {
  385.         Sys_Printf("Undo_AddBrushList: WARNING adding brushes after entity.\n");
  386.     }
  387.     //copy the brushes to the undo
  388.     for (pBrush = brushlist->next ; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next)
  389.     {
  390.         //if the brush is already in the undo
  391.         if (Undo_BrushInUndo(g_lastundo, pBrush))
  392.             continue;
  393.         // do we need to store this brush's entity in the undo?
  394.         // if it's a fixed size entity, the brush that reprents it is not really relevant, it's used for selecting and moving around
  395.         // what we want to store for undo is the owner entity, epairs and origin/angle stuff
  396.         //++timo FIXME: if the entity is not fixed size I don't know, so I don't do it yet
  397.         if (pBrush->owner->eclass->fixedsize == 1)
  398.             Undo_AddEntity( pBrush->owner );
  399.         //clone the brush
  400.         brush_t* pClone = Brush_FullClone(pBrush);
  401.         //save the ID of the owner entity
  402.         pClone->ownerId = pBrush->owner->entityId;
  403.         //save the old undo ID from previous undos
  404.         pClone->undoId = pBrush->undoId;
  405.         Brush_AddToList (pClone, &g_lastundo->brushlist);
  406.         //
  407.         g_undoMemorySize += Brush_MemorySize(pClone);
  408.     }
  409. }
  410.  
  411. /*
  412. =============
  413. Undo_EndBrush
  414. =============
  415. */
  416. void Undo_EndBrush(brush_t *pBrush)
  417. {
  418.     if (!g_lastundo)
  419.     {
  420.         //Sys_Printf("Undo_End: no last undo.\n");
  421.         return;
  422.     }
  423.     if (g_lastundo->done)
  424.     {
  425.         //Sys_Printf("Undo_End: last undo already finished.\n");
  426.         return;
  427.     }
  428.     pBrush->undoId = g_lastundo->id;
  429. }
  430.  
  431. /*
  432. =============
  433. Undo_EndBrushList
  434. =============
  435. */
  436. void Undo_EndBrushList(brush_t *brushlist)
  437. {
  438.     if (!g_lastundo)
  439.     {
  440.         //Sys_Printf("Undo_End: no last undo.\n");
  441.         return;
  442.     }
  443.     if (g_lastundo->done)
  444.     {
  445.         //Sys_Printf("Undo_End: last undo already finished.\n");
  446.         return;
  447.     }
  448.     for (brush_t* pBrush = brushlist->next; pBrush != NULL && pBrush != brushlist; pBrush=pBrush->next)
  449.     {
  450.         pBrush->undoId = g_lastundo->id;
  451.     }
  452. }
  453.  
  454. /*
  455. =============
  456. Undo_AddEntity
  457. =============
  458. */
  459. void Undo_AddEntity(entity_t *entity)
  460. {
  461.     entity_t* pClone;
  462.  
  463.     if (!g_lastundo)
  464.     {
  465.         Sys_Printf("Undo_AddEntity: no last undo.\n");
  466.         return;
  467.     }
  468.     //if the entity is already in the undo
  469.     if (Undo_EntityInUndo(g_lastundo, entity))
  470.         return;
  471.     //clone the entity
  472.     pClone = Entity_Clone(entity);
  473.     //NOTE: Entity_Clone adds the entity to the entity list
  474.     //        so we remove it from that list here
  475.     Entity_RemoveFromList(pClone);
  476.     //save the old undo ID for previous undos
  477.     pClone->undoId = entity->undoId;
  478.     //save the entity ID (we need a full clone)
  479.     pClone->entityId = entity->entityId;
  480.     //
  481.     Entity_AddToList(pClone, &g_lastundo->entitylist);
  482.     //
  483.     g_undoMemorySize += Entity_MemorySize(pClone);
  484. }
  485.  
  486. /*
  487. =============
  488. Undo_EndEntity
  489. =============
  490. */
  491. void Undo_EndEntity(entity_t *entity)
  492. {
  493.     if (!g_lastundo)
  494.     {
  495.         //Sys_Printf("Undo_End: no last undo.\n");
  496.         return;
  497.     }
  498.     if (g_lastundo->done)
  499.     {
  500.         //Sys_Printf("Undo_End: last undo already finished.\n");
  501.         return;
  502.     }
  503.     if (entity == world_entity)
  504.     {
  505.         //Sys_Printf("Undo_AddEntity: undo on world entity.\n");
  506.         //NOTE: we never delete the world entity when undoing an operation
  507.         //        we only transfer the epairs
  508.         return;
  509.     }
  510.     entity->undoId = g_lastundo->id;
  511. }
  512.  
  513. /*
  514. =============
  515. Undo_End
  516. =============
  517. */
  518. void Undo_End(void)
  519. {
  520.     if (!g_lastundo)
  521.     {
  522.         //Sys_Printf("Undo_End: no last undo.\n");
  523.         return;
  524.     }
  525.     if (g_lastundo->done)
  526.     {
  527.         //Sys_Printf("Undo_End: last undo already finished.\n");
  528.         return;
  529.     }
  530.     g_lastundo->done = true;
  531.  
  532.     //undo memory size is bound to a max
  533.     while (g_undoMemorySize > g_undoMaxMemorySize)
  534.     {
  535.         //always keep one undo
  536.         if (g_undolist == g_lastundo) break;
  537.         Undo_FreeFirstUndo();
  538.     }
  539.     //
  540.     //Sys_Printf("undo size = %d, undo memory = %d\n", g_undoSize, g_undoMemorySize);
  541. }
  542.  
  543. /*
  544. =============
  545. Undo_Undo
  546. =============
  547. */
  548. void Undo_Undo(void)
  549. {
  550.     undo_t *undo, *redo;
  551.     brush_t *pBrush, *pNextBrush;
  552.     entity_t *pEntity, *pNextEntity, *pUndoEntity;
  553.  
  554.     if (!g_lastundo)
  555.     {
  556.         Sys_Printf("Nothing left to undo.\n");
  557.         return;
  558.     }
  559.     if (!g_lastundo->done)
  560.     {
  561.         Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n");
  562.     }
  563.     // get the last undo
  564.     undo = g_lastundo;
  565.     if (g_lastundo->prev) g_lastundo->prev->next = NULL;
  566.     else g_undolist = NULL;
  567.     g_lastundo = g_lastundo->prev;
  568.  
  569.     //allocate a new redo
  570.     redo = (undo_t *) malloc(sizeof(undo_t));
  571.     if (!redo) return;
  572.     memset(redo, 0, sizeof(undo_t));
  573.     redo->brushlist.next = &redo->brushlist;
  574.     redo->brushlist.prev = &redo->brushlist;
  575.     redo->entitylist.next = &redo->entitylist;
  576.     redo->entitylist.prev = &redo->entitylist;
  577.     if (g_lastredo) g_lastredo->next = redo;
  578.     else g_redolist = redo;
  579.     redo->prev = g_lastredo;
  580.     redo->next = NULL;
  581.     g_lastredo = redo;
  582.     redo->time = Sys_DoubleTime();
  583.     redo->id = g_redoId++;
  584.     redo->done = true;
  585.     redo->operation = undo->operation;
  586.  
  587.     //reset the redo IDs of all brushes using the new ID
  588.     for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next)
  589.     {
  590.         if (pBrush->redoId == redo->id)
  591.         {
  592.             pBrush->redoId = 0;
  593.         }
  594.     }
  595.     for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next)
  596.     {
  597.         if (pBrush->redoId == redo->id)
  598.         {
  599.             pBrush->redoId = 0;
  600.         }
  601.     }
  602.     //reset the redo IDs of all entities using thew new ID
  603.     for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next)
  604.     {
  605.         if (pEntity->redoId == redo->id)
  606.         {
  607.             pEntity->redoId = 0;
  608.         }
  609.     }
  610.  
  611.     // remove current selection
  612.     Select_Deselect();
  613.     // move "created" brushes to the redo
  614.     for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush)
  615.     {
  616.         pNextBrush = pBrush->next;
  617.         if (pBrush->undoId == undo->id)
  618.         {
  619.             //Brush_Free(pBrush);
  620.             //move the brush to the redo
  621.             Brush_RemoveFromList(pBrush);
  622.             Brush_AddToList(pBrush, &redo->brushlist);
  623.             //make sure the ID of the owner is stored
  624.             pBrush->ownerId = pBrush->owner->entityId;
  625.             //unlink the brush from the owner entity
  626.             Entity_UnlinkBrush(pBrush);
  627.         }
  628.     }
  629.     // move "created" entities to the redo
  630.     for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
  631.     {
  632.         pNextEntity = pEntity->next;
  633.         if (pEntity->undoId == undo->id)
  634.         {
  635.             // check if this entity is in the undo
  636.             for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next)
  637.             {
  638.                 // move brushes to the undo entity
  639.                 if (pUndoEntity->entityId == pEntity->entityId)
  640.                 {
  641.                     pUndoEntity->brushes.next = pEntity->brushes.next;
  642.                     pUndoEntity->brushes.prev = pEntity->brushes.prev;
  643.                     pEntity->brushes.next = &pEntity->brushes;
  644.                     pEntity->brushes.prev = &pEntity->brushes;
  645.                 }
  646.             }
  647.             //
  648.             //Entity_Free(pEntity);
  649.             //move the entity to the redo
  650.             Entity_RemoveFromList(pEntity);
  651.             Entity_AddToList(pEntity, &redo->entitylist);
  652.         }
  653.     }
  654.     // add the undo entities back into the entity list
  655.     for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next)
  656.     {
  657.         g_undoMemorySize -= Entity_MemorySize(pEntity);
  658.         //if this is the world entity
  659.         if (pEntity->entityId == world_entity->entityId)
  660.         {
  661.             //free the epairs of the world entity
  662.             Entity_FreeEpairs(world_entity);
  663.             //set back the original epairs
  664.             world_entity->epairs = pEntity->epairs;
  665.             // unhook the epairs and free the world_entity clone that stored the epairs
  666.             pEntity->epairs = NULL;
  667.             Entity_Free(pEntity);
  668.         }
  669.         else
  670.         {
  671.             Entity_RemoveFromList(pEntity);
  672.             Entity_AddToList(pEntity, &entities);
  673.             pEntity->redoId = redo->id;
  674.         }
  675.     }
  676.     // add the undo brushes back into the selected brushes
  677.     for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next)
  678.     {
  679.         g_undoMemorySize -= Brush_MemorySize(pBrush);
  680.         Brush_RemoveFromList(pBrush);
  681.         Brush_AddToList(pBrush, &active_brushes);
  682.         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
  683.         {
  684.             if (pEntity->entityId == pBrush->ownerId)
  685.             {
  686.                 Entity_LinkBrush(pEntity, pBrush);
  687.                 break;
  688.             }
  689.         }
  690.         //if the brush is not linked then it should be linked into the world entity
  691.         if (pEntity == NULL || pEntity == &entities)
  692.         {
  693.             Entity_LinkBrush(world_entity, pBrush);
  694.         }
  695.         //build the brush
  696.         //Brush_Build(pBrush);
  697.         Select_Brush(pBrush);
  698.         pBrush->redoId = redo->id;
  699.     }
  700.     //
  701.     Sys_Printf("%s undone.\n", undo->operation);
  702.     // free the undo
  703.     g_undoMemorySize -= sizeof(undo_t);
  704.     free(undo);
  705.     g_undoSize--;
  706.     g_undoId--;
  707.     if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize;
  708.     //
  709.     g_bScreenUpdates = true; 
  710.     Sys_UpdateWindows(W_ALL);
  711. }
  712.  
  713. /*
  714. =============
  715. Undo_Redo
  716. =============
  717. */
  718. void Undo_Redo(void)
  719. {
  720.     undo_t *redo;
  721.     brush_t *pBrush, *pNextBrush;
  722.     entity_t *pEntity, *pNextEntity, *pRedoEntity;
  723.  
  724.     if (!g_lastredo)
  725.     {
  726.         Sys_Printf("Nothing left to redo.\n");
  727.         return;
  728.     }
  729.     if (g_lastundo)
  730.     {
  731.         if (!g_lastundo->done)
  732.         {
  733.             Sys_Printf("WARNING: last undo not finished.\n");
  734.         }
  735.     }
  736.     // get the last redo
  737.     redo = g_lastredo;
  738.     if (g_lastredo->prev) g_lastredo->prev->next = NULL;
  739.     else g_redolist = NULL;
  740.     g_lastredo = g_lastredo->prev;
  741.     //
  742.     Undo_GeneralStart(redo->operation);
  743.     // remove current selection
  744.     Select_Deselect();
  745.     // move "created" brushes back to the last undo
  746.     for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush)
  747.     {
  748.         pNextBrush = pBrush->next;
  749.         if (pBrush->redoId == redo->id)
  750.         {
  751.             //move the brush to the undo
  752.             Brush_RemoveFromList(pBrush);
  753.             Brush_AddToList(pBrush, &g_lastundo->brushlist);
  754.             g_undoMemorySize += Brush_MemorySize(pBrush);
  755.             pBrush->ownerId = pBrush->owner->entityId;
  756.             Entity_UnlinkBrush(pBrush);
  757.         }
  758.     }
  759.     // move "created" entities back to the last undo
  760.     for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
  761.     {
  762.         pNextEntity = pEntity->next;
  763.         if (pEntity->redoId == redo->id)
  764.         {
  765.             // check if this entity is in the redo
  766.             for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next)
  767.             {
  768.                 // move brushes to the redo entity
  769.                 if (pRedoEntity->entityId == pEntity->entityId)
  770.                 {
  771.                     pRedoEntity->brushes.next = pEntity->brushes.next;
  772.                     pRedoEntity->brushes.prev = pEntity->brushes.prev;
  773.                     pEntity->brushes.next = &pEntity->brushes;
  774.                     pEntity->brushes.prev = &pEntity->brushes;
  775.                 }
  776.             }
  777.             //
  778.             //Entity_Free(pEntity);
  779.             //move the entity to the redo
  780.             Entity_RemoveFromList(pEntity);
  781.             Entity_AddToList(pEntity, &g_lastundo->entitylist);
  782.             g_undoMemorySize += Entity_MemorySize(pEntity);
  783.         }
  784.     }
  785.     // add the undo entities back into the entity list
  786.     for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next)
  787.     {
  788.         //if this is the world entity
  789.         if (pEntity->entityId == world_entity->entityId)
  790.         {
  791.             //free the epairs of the world entity
  792.             Entity_FreeEpairs(world_entity);
  793.             //set back the original epairs
  794.             world_entity->epairs = pEntity->epairs;
  795.             //free the world_entity clone that stored the epairs
  796.             Entity_Free(pEntity);
  797.         }
  798.         else
  799.         {
  800.             Entity_RemoveFromList(pEntity);
  801.             Entity_AddToList(pEntity, &entities);
  802.         }
  803.     }
  804.     // add the redo brushes back into the selected brushes
  805.     for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next)
  806.     {
  807.         Brush_RemoveFromList(pBrush);
  808.         Brush_AddToList(pBrush, &active_brushes);
  809.         for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity)
  810.         {
  811.             if (pEntity->entityId == pBrush->ownerId)
  812.             {
  813.                 Entity_LinkBrush(pEntity, pBrush);
  814.                 break;
  815.             }
  816.         }
  817.         //if the brush is not linked then it should be linked into the world entity
  818.         if (pEntity == NULL || pEntity == &entities)
  819.         {
  820.             Entity_LinkBrush(world_entity, pBrush);
  821.         }
  822.         //build the brush
  823.         //Brush_Build(pBrush);
  824.         Select_Brush(pBrush);
  825.     }
  826.     //
  827.     Undo_End();
  828.     //
  829.     Sys_Printf("%s redone.\n", redo->operation);
  830.     //
  831.     g_redoId--;
  832.     // free the undo
  833.     free(redo);
  834.     //
  835.     g_bScreenUpdates = true; 
  836.     Sys_UpdateWindows(W_ALL);
  837. }
  838.  
  839. /*
  840. =============
  841. Undo_RedoAvailable
  842. =============
  843. */
  844. int Undo_RedoAvailable(void)
  845. {
  846.     if (g_lastredo) return true;
  847.     return false;
  848. }
  849.  
  850. /*
  851. =============
  852. Undo_UndoAvailable
  853. =============
  854. */
  855. int Undo_UndoAvailable(void)
  856. {
  857.     if (g_lastundo)
  858.     {
  859.         if (g_lastundo->done)
  860.             return true;
  861.     }
  862.     return false;
  863. }
  864.